package com.easy.activiti.util;


import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * @author zhouchuang
 * 2024-10-09 10:26:10
 */
public class MySnowflakeGenerator {
    private final static MySnowflake snowflake = new MySnowflake(new Date(124,01,01), 0,0,false);
    public static Long next() {
        return snowflake.nextId();
    }

    public static void main(String[] args) throws Exception{
        Set<Long> set = new HashSet<Long>();
        for (int i=0;i<10000;i++){
            set.add(next());
        }
        System.out.println(set.size());
        System.out.println(set);
    }

    private static class MySnowflake implements Serializable {
        private static final long serialVersionUID = 1L;
        public static long DEFAULT_TWEPOCH = 1288834974657L;
        public static long DEFAULT_TIME_OFFSET = 2000L;
        private static final long WORKER_ID_BITS = 5L;
        private static final long MAX_WORKER_ID = 31L;
        private static final long DATA_CENTER_ID_BITS = 5L;
        private static final long MAX_DATA_CENTER_ID = 31L;
        private static final long SEQUENCE_BITS = 12L;
        private static final long WORKER_ID_SHIFT = 12L;
        private static final long DATA_CENTER_ID_SHIFT = 17L;
        private static final long TIMESTAMP_LEFT_SHIFT = 22L;
        private static final long SEQUENCE_MASK = 4095L;
        private final long twepoch;
        private final long workerId;
        private final long dataCenterId;
        private final boolean useSystemClock;
        private final long timeOffset;
        private final long randomSequenceLimit;
        private long sequence;
        private long lastTimestamp;



        public MySnowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock) {
            this(epochDate, workerId, dataCenterId, isUseSystemClock, DEFAULT_TIME_OFFSET);
        }

        public MySnowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock, long timeOffset) {
            this(epochDate, workerId, dataCenterId, isUseSystemClock, timeOffset, 0L);
        }

        public MySnowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock, long timeOffset, long randomSequenceLimit) {
            this.sequence = 0L;
            this.lastTimestamp = -1L;
            this.twepoch = null != epochDate ? epochDate.getTime()>>10 : DEFAULT_TWEPOCH>>10;
            this.workerId = workerId;
            this.dataCenterId = dataCenterId;
            this.useSystemClock = isUseSystemClock;
            this.timeOffset = timeOffset;
            this.randomSequenceLimit = randomSequenceLimit;
        }


        public synchronized long nextId() {
            long timestamp = this.genTime();
            if (timestamp < this.lastTimestamp) {
                if (this.lastTimestamp - timestamp >= this.timeOffset) {
                    throw new IllegalStateException(String.format("Clock moved backwards. Refusing to generate id for %sms", this.lastTimestamp - timestamp));
                }

                timestamp = this.lastTimestamp;
            }

            if (timestamp == this.lastTimestamp) {
                long sequence = this.sequence + 1L & 4095L;
                if (sequence == 0L) {
                    timestamp = this.tilNextMillis(this.lastTimestamp);
                }
                this.sequence = sequence;
            }else {
                this.sequence = 0L;
            }

            this.lastTimestamp = timestamp;
            return ((timestamp - this.twepoch)  << 12 ) | this.sequence;
        }

        public String nextIdStr() {
            return Long.toString(this.nextId());
        }

        private long tilNextMillis(long lastTimestamp) {
            long timestamp;
            for(timestamp = this.genTime(); timestamp == lastTimestamp; timestamp = this.genTime()) {
            }

            if (timestamp < lastTimestamp) {
                throw new IllegalStateException(String.format("Clock moved backwards. Refusing to generate id for %sms", lastTimestamp - timestamp));
            } else {
                return timestamp;
            }
        }

        //改成秒
        private long genTime() {
            return  System.currentTimeMillis()>>10;
        }
    }

}
